package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.enumeration.OperationType;
import com.sky.utils.ThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 自定义切面，实现公共字段自动填充处理逻辑
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    /**
     * 切入点
     */
    @Pointcut("execution(* com.sky.mapper..*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut() {
    }

    /**
     * 前置通知，在通知中进行公共字段的赋值
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("开始进行公共字段自动填充...");

        // 获取目标方法（被增强的方法）对象
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method targetMethodObj = signature.getMethod();


        // 判断其删是否标注Autofill注解，有则获取
        if (targetMethodObj.isAnnotationPresent(AutoFill.class)) {
            AutoFill autoFillObj = targetMethodObj.getAnnotation(AutoFill.class);

            // 判断增强操作的类型
            OperationType operationType = autoFillObj.value();

            // 获取目标方法实参
            Object[] args = joinPoint.getArgs();
            // 我们要增强的是一个实体参数的方法
            if (args != null && args.length == 1) {
                // 获取唯一的实参对象
                Object entity = args[0];

                // 通过反射为实参中公共字段设置值（获取增强操作类型不同，设置稍有差异）

                // 更新。获取更新id和更新时间的setter并调用
                try {
                    // 获取目标方法
                    Method setUpdateTimeMethodObj =
                            entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                    Method setUpdateUserMethodObj =
                            entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                    // 调用目标方法
                    setUpdateTimeMethodObj.invoke(entity, LocalDateTime.now());
                    setUpdateUserMethodObj.invoke(entity, ThreadLocalUtil.getCurrentId());

                    // 新增。获取新增用户id和新增时间的setter并调用
                    if (OperationType.INSERT == operationType) {
                        // 获取目标方法
                        Method setCreateTimeMethodObj =
                                entity.getClass().getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                        Method setCreateUserMethodObj =
                                entity.getClass().getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);

                        // 调用目标方法
                        setCreateTimeMethodObj.invoke(entity, LocalDateTime.now());
                        setCreateUserMethodObj.invoke(entity, ThreadLocalUtil.getCurrentId());
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
    }
}
